#include<iostream>
#include<unistd.h>
#include <cstring> 
#include<cerrno>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;


// fork之后子进程是能拿到父进程的数据的 --- 通信吗？写时拷贝，对方都看不到
// char buffer[1024]; // 不行的

const int size = 1024;

//再写一些其他内容，Pid带进来，再来个计数器
std::string getOtherMessage()
{
    static int cnt = 0;
    std::string messageid = std::to_string(cnt); // stoi -> string -> int
    cnt++;
    pid_t self_id = getpid();
    std::string stringpid = std::to_string(self_id);

    std::string message = "messageid: ";
    message += messageid;
    message += " my pid is : ";
    message += stringpid;

    return message;
}

// 子进程进行写入 形参是写文件描述符
void SubProcessWrite(int wfd)
{
    int pipesize = 0;
    std::string message = "father, I am your son prcess!";
    char c = 'A';
    while (true)
    {
        std::cerr << "+++++++++++++++++++++++++++++++++" << std::endl;
        std::string info = message + getOtherMessage(); // 这条消息，就是我们子进程发给父进程的消息
        //发送消息本质就是向管道文件写入，用write系统调用即可
        write(wfd, info.c_str(), info.size()); // 写入管道的时候，没有写入\0, 有没有必要？没有必要
        
        std::cerr << info << std::endl;
        
        // sleep(1); // 子进程写慢一点

        //验证管道有多大--子进程一直写每次写一个字符 父进程不读sleep(500)
        // write(wfd, &c, 1);
        // std::cout << "pipesize: " << ++pipesize << " write charator is : "<< c++ << std::endl;
        // // if(c == 'G') break;

        // sleep(1);
    }

    std::cout << "child quit ..." << std::endl;
}

// 父进程进行读取
void FatherProcessRead(int rfd)
{
    char inbuffer[size]; // c99 , gnu g99
    while (true)
    {
        sleep(2);
        std::cout << "-------------------------------------------" << std::endl;
        // sleep(500);
        //ssize_t是有符号整数int ；size_t是无符号整数
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer) - 1); // sizeof(inbuffer)->strlen(inbuffer);
        if (n > 0)
        {
            inbuffer[n] = 0; // == '\0'
            std::cout  << inbuffer << std::endl;
        }
        else if (n == 0)
        {
            // 如果read的返回值是0，表示写端直接关闭了，我们读到了文件的结尾
            std::cout << "client quit, father get return val: " << n << " father quit too!" << std::endl;
            break;
        }
        else if(n < 0)
        {
            std::cerr << "read error" << std::endl;
            break;
        }

        // sleep(1);
        // break;
    }
}



int main(){
    //创建管道
    int pipefd[2];
    int n = pipe(pipefd);//输出型参数,读写描述符被放在数组里
    //成功返回0 失败-1 设置错误码
    if (n != 0)
    {
        std::cerr << "errno: " << errno << ": "
                  << "errstring : " << strerror(errno) << std::endl;
        return 1;
    }
    //成功
    //pipefd[0]->0->r(嘴巴 - 读)  pipefd[1]->1->w(笔->写)
    //3读   4写 符合我们对父进程的预期
    std::cout << "pipefd[0]: " << pipefd[0] << ", pipefd[1]: " << pipefd[1] << std::endl;
    sleep(1);

    // 2. 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        std::cout << "子进程关闭不需要的fd了, 准备发消息了" << std::endl;
        sleep(1);
        // 子进程 --- write 关闭pipefd[0]
        // 3. 关闭不需要的fd
        close(pipefd[0]);

        // if(fork() > 0) exit(0);//验证爷孙之间的通信，也可以

        SubProcessWrite(pipefd[1]);
        close(pipefd[1]);//结束之后不用了把1也关了，这个可不写
        exit(0);
    }

    std::cout << "父进程关闭不需要的fd了, 准备收消息了" << std::endl;
    sleep(1);
    // 父进程 --- read
    // 3. 关闭不需要的fd
    close(pipefd[1]);
    FatherProcessRead(pipefd[0]);
    std::cout << "5s, father close rfd" << std::endl;
    sleep(5);
    close(pipefd[0]);

    int status = 0;
    //父进程wait操作 不看错误信息把status设为nullptr即可 
    pid_t rid = waitpid(id, &status, 0);
    if (rid > 0)
    {
        std::cout << "wait child process done, exit sig: " << (status&0x7f) << std::endl;//退出信号13 SIGPIPE
        std::cout << "wait child process done, exit code(ign): " << ((status>>8)&0xFF) << std::endl;//退出码没有意义
    }
     
    return 0;
}